#pragma once

#include <iostream>
#include <string>
#include <sys/types.h>
#include <sys/shm.h>
#include <sys/ipc.h>
#include "Comm.hpp"
using namespace std;

#define Creator "creator"
#define User "user"
const int gsize = 4096;
const int gmode = 0666;
const int gaultid = -1;
const string pathname = ".";
const int projid = 0x66;

class Shm
{
private:
    void Attach() // 挂接
    {
        _start_shm = shmat(_shmid, nullptr, 0);
        if ((long long)_start_shm < 0)
        {
            ERR_EXIT("shmat");
        }
        cout << "Attach success!" << endl;
    }

    void Detach() // 取消挂接
    {
        int n = shmdt(_start_shm);
        if (n == 0)
        {
            cout << "Detach success!" << endl;
        }
    }

    void CreateHelp(int flag) // 创建内存空间
    {
        printf("key:0x%x\n", _key);
        _shmid = shmget(_key, _size, flag);
        if (_shmid < 0)
        {
            ERR_EXIT("shmget");
        }
        cout << "shmget success!" << endl;
    }

    // 用户权限设置
    void Create() // 创建者
    {
        CreateHelp(IPC_CREAT | IPC_EXCL | gmode);
    }

    void Get() // 用户使用者
    {
        CreateHelp(IPC_CREAT);
    }

    void Destroy() // 销毁
    {
        Detach();
        if (_user_type == Creator)
        {
            int n = shmctl(_shmid, IPC_RMID, nullptr);
            if (n == 0)
            {
                cout << "共享内存销毁成功" << endl;
            }
            else
            {
               ERR_EXIT("shmctl");
            }
        }
    }

public:
    Shm(const string &user, int projid, const string &pathname)
        : _user_type(user), _size(gsize), _start_shm(nullptr), _shmid(gaultid), _num(0)
    {
        _key = ftok(pathname.c_str(), projid); // 现在是这里有问题
        if (_key < 0)
        {
            ERR_EXIT("ftok");
        }
        if (_user_type == Creator)
        {
            Create();
        }
        else if (_user_type == User)
        {
            Get();
        }
        else
        {
        }
        Attach();
    }

    ~Shm()
    {
        cout << _user_type << endl;
        if (_user_type == Creator)
        {
            Destroy();
        }
    }

    void Print() // 打印key值和起始地址
    {
        struct shmid_ds ds;
        int n = shmctl(_shmid, IPC_STAT, &ds);
        printf("key:0x%x\n", ds.shm_perm.__key);
        printf("shm_segsz:%ld\n", ds.shm_segsz);
    }

    int size()
    {
        return _size;
    }

    void *_memstart()
    {
        printf("_memstart:%p\n", _start_shm);
        return _start_shm;
    }

private:
    string _user_type;
    key_t _key;
    int _size;
    void *_start_shm;
    int _shmid;
    int _num;
};